package cn.kgc.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import cn.kgc.entity.Menus;
import cn.kgc.entity.RolesMenus;
import cn.kgc.form.MenusAddForm;
import cn.kgc.form.MenusUpdateForm;
import cn.kgc.service.MenusService;
import cn.kgc.service.RolesMenusService;
import cn.kgc.util.SystemUtil;
import cn.kgc.util.resultutil.ResultConstant;
import cn.kgc.util.resultutil.exception.HttpException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * @author YC
 */
@RestController
@RequestMapping("/menus")
@Api(tags = "菜单管理接口")
@Validated
@Slf4j
@CrossOrigin
public class MenusController {

    @Resource
    private MenusService menusService;
    @Resource
    private RolesMenusService rolesMenusService;

    @PostMapping("/list")
    @ApiOperation(value = "查询菜单列表")
    public List<Menus> list(@RequestBody Map<String, Object> map) {
        // 传入参数按参数查询
        String menuCode = MapUtil.getStr(map, "menuCode");
        String menuName = MapUtil.getStr(map, "menuName");
        LambdaQueryWrapper<Menus> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(menuCode), Menus::getMenuCode, menuCode)
                .eq(StringUtils.isNotBlank(menuName), Menus::getMenuName, menuName);
        List<Menus> queryList = menusService.list(wrapper);
        // 没有传入参数则查询所有菜单
        // 前端的El需要树形数据结构 所以统一处理为JSON格式树形结构返回
        if (StrUtil.isBlank(menuCode) && StrUtil.isBlank(menuName)) {
            queryList = SystemUtil.tree(queryList);
        }
        return queryList;
    }

    @GetMapping("/detail/{id}")
    @ApiOperation(value = "查看菜单详细")
    @Cacheable(value = "menus#360", key = "#root.methodName + #id")
    public Menus detail(@PathVariable Integer id) {
        return menusService.getById(id);
    }

    @PostMapping("/save")
    @ApiOperation(value = "新增菜单信息")
    public boolean save(@RequestBody MenusAddForm form) {
        // 菜单名称不能重复
        checkMenuNameRepeat(form.getMenuName(), null);
        // 菜单编码使用首字母拼音
        String menuCode = PinyinUtil.getFirstLetter(form.getMenuName(), "");
        //  新增逻辑
        Menus menus = new Menus();
        BeanUtil.copyProperties(form, menus);
        menus.setMenuCode(menuCode);
        return menusService.save(menus);
    }

    @PostMapping("/update")
    @ApiOperation(value = "更新菜单信息")
    @CacheEvict(value = "menus#360", key = "'detail' + #form.getId()")
    public boolean update(@RequestBody MenusUpdateForm form) {
        // 菜单名称不能重复
        checkMenuNameRepeat(form.getMenuName(), form.getId());
        // 菜单编码使用首字母拼音
        String menuCode = PinyinUtil.getFirstLetter(form.getMenuName(), "");
        // 更新逻辑
        Menus menus = menusService.getById(form.getId());
        if (menus != null) {
            BeanUtil.copyProperties(form, menus);
            menus.setMenuCode(menuCode);
            return menusService.updateById(menus);
        }
        return false;
    }

    @DeleteMapping("/delete/{id}")
    @ApiOperation(value = "根据主键删除")
    @CacheEvict(value = "menus", key = "'detail' + #id")
    @ApiImplicitParam(name = "id", value = "主键", paramType = "path", dataType = "string")
    public boolean delete(@PathVariable Integer id) {
        // 菜单下有子菜单不允许删除
        checkMenuHasChild(id);
        // 菜单被使用不允许删除
        checkMenuBeUsed(id);
        return menusService.removeById(id);
    }

//============================= 菜单管理接口自定义方法 ===========================

    private void checkMenuNameRepeat(String menuName, String menuId) {
        LambdaQueryWrapper<Menus> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menus::getMenuName, menuName)
                .ne(menuId != null, Menus::getId, menuId);
        if (menusService.count(wrapper) > 0) {
            throw new HttpException(ResultConstant.MENU_INSERT_UPDATE_ERROR_REPEAT);
        }
    }

    private void checkMenuHasChild(Integer id) {
        LambdaQueryWrapper<Menus> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menus::getParentId, id);
        if (menusService.count(wrapper) > 0) {
            throw new HttpException(ResultConstant.MENU_DELETE_ERROR_CHILD);
        }
    }

    private void checkMenuBeUsed(Integer id) {
        LambdaQueryWrapper<RolesMenus> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RolesMenus::getMid, id);
        if (rolesMenusService.count(wrapper) > 0) {
            throw new HttpException(ResultConstant.MENU_DELETE_ERROR_USED);
        }
    }

}
